package com.zj.dmsproxy.wrapper;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zj.baseproxy.utils.ClassUtil;
import com.zj.dmsproxy.enums.QueryEnum;
import com.zj.baseproxy.utils.LambdaUtil;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;

/**
 * @author arthur_zhou
 * @date 2023/11/2 17:29
 */
@Getter
public class DmsWrapper {

    @JSONField(serialzeFeatures = SerializerFeature.WriteMapNullValue)
    private Map<String, Object> query;
    private GroupWrapper group;
    @JSONField(name = "num_to_return")
    private Integer numToReturn;
    @JSONField(name = "num_to_skip")
    private Integer numToSkip;
    @JSONField(name = "orderby")
    private LinkedHashMap<String, Integer> orderBy;
    private LinkedHashMap<String, Integer> fields;
    @JSONField(name = "count_only")
    private Integer countOnly;
    @JSONField(name = "data_only")
    private Integer dataOnly;

    public DmsWrapper() {
    }

    public DmsWrapper(DmsWrapper dmsWrapper) {
        if (Objects.isNull(dmsWrapper)) {
            return;
        }
        if (Objects.nonNull(dmsWrapper.getQuery())) {
            this.query = new LinkedHashMap<>(dmsWrapper.getQuery());
        }
        if (Objects.nonNull(dmsWrapper.getGroup())) {
            this.group = new GroupWrapper(dmsWrapper.getGroup());
        }
        this.numToReturn = dmsWrapper.getNumToReturn();
        this.numToSkip = dmsWrapper.getNumToSkip();
        if (Objects.nonNull(dmsWrapper.getOrderBy())) {
            this.orderBy = new LinkedHashMap<>(dmsWrapper.getOrderBy());
        }
        if (Objects.nonNull(dmsWrapper.getFields())) {
            this.fields = new LinkedHashMap<>(dmsWrapper.getFields());
        }
    }

    /**
     * 分组，多次调用会覆盖
     *
     * @param groupWrapper 分组拼接器
     * @return 自己
     */
    public DmsWrapper group(GroupWrapper groupWrapper) {
        if (Objects.nonNull(groupWrapper) && CollectionUtil.isNotEmpty(groupWrapper.getGroupBy())) {
            this.group = groupWrapper;
        }
        return this;
    }

    /**
     * 分组，多次调用会覆盖
     *
     * @param consumer 函数式接口
     * @return 自己
     */
    public DmsWrapper group(Consumer<GroupWrapper> consumer) {
        GroupWrapper groupWrapper = new GroupWrapper();
        consumer.accept(groupWrapper);
        return group(groupWrapper);
    }

    /**
     * 查询条件，多次调用会覆盖
     *
     * @param queryWrapper 查询拼接器
     * @return 自己
     */
    public DmsWrapper query(QueryWrapper queryWrapper) {
        if (Objects.nonNull(queryWrapper) && CollectionUtil.isNotEmpty(queryWrapper.getQueryList())) {
            this.query = queryWrapper.toCondition();
        }
        return this;
    }

    /**
     * 查询条件，多次调用会覆盖
     *
     * @param consumer 函数式接口
     * @return 自己
     */
    public DmsWrapper query(Consumer<QueryWrapper> consumer) {
        return query(true, consumer);
    }

    /**
     * 查询条件，多次调用会覆盖
     *
     * @param check    校验值是否为空。true时，空值不放入条件
     * @param consumer 函数式接口
     * @return 自己
     */
    public DmsWrapper query(boolean check, Consumer<QueryWrapper> consumer) {
        QueryWrapper queryWrapper = new QueryWrapper(QueryEnum.AND, false, check);
        consumer.accept(queryWrapper);
        return query(queryWrapper);
    }

    /**
     * 跳过，多次调用会覆盖
     *
     * @param num 跳过
     * @return 自己
     */
    public DmsWrapper skip(Integer num) {
        this.numToSkip = num;
        return this;
    }

    /**
     * 返回条数，多次调用会覆盖
     *
     * @param num 返回条数
     * @return 自己
     */
    public DmsWrapper limit(Integer num) {
        this.numToReturn = num;
        return this;
    }

    /**
     * 分页，多次调用会覆盖
     *
     * @param numToSkip   跳过
     * @param numToReturn 返回条数
     * @return 自己
     */
    public DmsWrapper limit(Integer numToSkip, Integer numToReturn) {
        this.numToSkip = numToSkip;
        this.numToReturn = numToReturn;
        return this;
    }

    /**
     * 查询字段，只新增不覆盖
     *
     * @param fields 字段
     * @return 自己
     */
    public DmsWrapper select(String... fields) {
        if (Objects.nonNull(fields) && fields.length > 0) {
            initFields();
            for (String field : fields) {
                this.fields.put(field, 1);
            }
        }
        return this;
    }

    /**
     * 查询字段，只新增不覆盖
     *
     * @param fields 字段
     * @return 自己
     */
    public DmsWrapper select(Collection<String> fields) {
        if (CollectionUtil.isNotEmpty(fields)) {
            initFields();
            for (String field : fields) {
                this.fields.put(field, 1);
            }
        }
        return this;
    }

    /**
     * 查询字段，只新增不覆盖
     * 优先使用@JSONField里的name
     * 会驼峰转下划线
     *
     * @param clazz 实体类class
     * @return 自己
     */
    public DmsWrapper select(Class<?> clazz) {
        if (Objects.nonNull(clazz) && !ClassUtil.isBaseType(clazz)) {
            Field[] allFields = FieldUtils.getAllFields(clazz);
            if (Objects.nonNull(allFields) && allFields.length > 0) {
                initFields();
                for (Field field : allFields) {
                    JSONField jsonField = AnnotatedElementUtils.getMergedAnnotation(field, JSONField.class);
                    String filed;
                    if (Objects.isNull(jsonField) || StringUtils.isEmpty(filed = jsonField.name())) {
                        filed = LambdaUtil.camelToUnderscore(field.getName());
                    }
                    this.fields.put(filed, 1);
                }
            }
        }
        return this;
    }

    /**
     * 顺序，只新增不覆盖
     *
     * @param fields 字段
     * @return 自己
     */
    public DmsWrapper orderByAsc(String... fields) {
        if (Objects.nonNull(fields) && fields.length > 0) {
            initOrderBy();
            for (String field : fields) {
                orderBy.put(field, 1);
            }
        }
        return this;
    }

    /**
     * 顺序，只新增不覆盖
     *
     * @param fields 字段
     * @return 自己
     */
    public DmsWrapper orderByAsc(Collection<String> fields) {
        if (CollectionUtil.isNotEmpty(fields)) {
            initOrderBy();
            for (String field : fields) {
                orderBy.put(field, 1);
            }
        }
        return this;
    }

    /**
     * 倒序，只新增不覆盖
     *
     * @param fields 字段
     * @return 自己
     */
    public DmsWrapper orderByDesc(String... fields) {
        if (Objects.nonNull(fields) && fields.length > 0) {
            initOrderBy();
            for (String field : fields) {
                orderBy.put(field, -1);
            }
        }
        return this;
    }

    /**
     * 倒序，只新增不覆盖
     *
     * @param fields 字段
     * @return 自己
     */
    public DmsWrapper orderByDesc(Collection<String> fields) {
        if (CollectionUtil.isNotEmpty(fields)) {
            initOrderBy();
            for (String field : fields) {
                orderBy.put(field, -1);
            }
        }
        return this;
    }

    /**
     * 只获取统计数
     *
     * @return 自己
     * @see DmsWrapper#dataOnly() 和其互斥
     */
    public DmsWrapper countOnly() {
        countOnly = 1;
        dataOnly = null;
        return this;
    }

    /**
     * 只获取数据列表
     *
     * @return 自己
     * @see DmsWrapper#countOnly() 和其互斥
     */
    public DmsWrapper dataOnly() {
        countOnly = null;
        dataOnly = 1;
        return this;
    }

    /**
     * 初始化排序map，线程不安全
     */
    private void initOrderBy() {
        if (Objects.isNull(orderBy)) {
            orderBy = new LinkedHashMap<>();
        }
    }

    /**
     * 初始化查询字段，线程不安全
     */
    private void initFields() {
        if (Objects.isNull(fields)) {
            fields = new LinkedHashMap<>();
        }
    }
}
